package laxproxy

import (
	"context"
	"fmt"
	"sync"
	"time"
)

type GenProtoMgr struct {
	/// 可使用的协议 <协议id, 协议信息>
	Protocols    map[uint32]ClientProtocolNode
	ProtocolList []ClientProtocolNode
	/// 接收web请求
	WebSendMsgChan chan *WebSendMsgNode
	/// web请求列表 <自增id, 请求的节点
	WebSendMsgQueue map[uint]*WebSendMsgNode
	/// 上面这个列表的自增id
	QueueIncKey uint
	/// 服务器返回的数据给web端显示
	ServerReplyChan chan *ServerReplyNode
}

var mgrOnce sync.Once
var instance *GenProtoMgr

func genProtoMgrInstance() *GenProtoMgr {
	mgrOnce.Do(func() {
		instance = &GenProtoMgr{
			Protocols:       make(map[uint32]ClientProtocolNode),
			WebSendMsgChan:  make(chan *WebSendMsgNode),
			WebSendMsgQueue: make(map[uint]*WebSendMsgNode),
			QueueIncKey:     0,
			ServerReplyChan: make(chan *ServerReplyNode),
		}
	})
	return instance
}

func RegisterClientProtocol(node ClientProtocolNode) {
	genProtoMgrInstance().Protocols[node.ProtoId] = node
	genProtoMgrInstance().ProtocolList = append(genProtoMgrInstance().ProtocolList, node)
}

func SendAndWait(webReq *WebSendMsgNode) {
	if !getProxyCtxMgr().Write2ServerByRoleId(webReq.RoleUid, webReq.SendMsg) {
		webReq.ch <- &WebReplyNode{
			code: 1,
			msg:  []byte("发送失败,已经下线?"),
		}
		return
	}
	if protoNode, ok := genProtoMgrInstance().Protocols[webReq.ProtoId]; ok {
		if protoNode.Timeout == 0 {
			webReq.ch <- &WebReplyNode{
				code: 1,
				msg:  []byte("发送成功..."),
			}
			return
		}
		genProtoMgrInstance().QueueIncKey++
		genProtoMgrInstance().WebSendMsgQueue[genProtoMgrInstance().QueueIncKey] = webReq
		go func(node *WebSendMsgNode, protocolNode ClientProtocolNode) {
			select {
			case <-node.ch:
			case <-time.After(time.Millisecond * protocolNode.Timeout):
				node.ch <- &WebReplyNode{
					code: 1,
					msg:  []byte(fmt.Sprintf("请求:%d 超时,角色:%d", node.ProtoId, node.RoleUid)),
				}
			}
		}(webReq, protoNode)
	}
}

func (mgr *GenProtoMgr) Start(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			break
		case webReq := <-mgr.WebSendMsgChan:
			SendAndWait(webReq)
		case svrReplay := <-mgr.ServerReplyChan:
			for k, v := range mgr.WebSendMsgQueue {
				if v.RoleUid == svrReplay.RoleUid && v.ProtoId == svrReplay.ProtoId {
					v.ch <- &WebReplyNode{
						code: 0,
						msg:  svrReplay.ReplyMsg,
					}
					delete(mgr.WebSendMsgQueue, k)
				}
			}
		}
	}
}
